package com.hs.live.gateway.filter;

import com.alibaba.nacos.shaded.com.google.common.base.Strings;
import com.hs.live.common.redis.key.LoginRedisKeyGenerate;
import com.hs.live.common.redis.utils.RedisLiveUtil;
import com.hs.live.gateway.properties.SkipUrlProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @Description: 校验token是否有效
 * @Author 胡尚
 * @Date: 2024/9/7 15:35
 */
@Slf4j
@Component
@EnableConfigurationProperties(value = {SkipUrlProperties.class})
public class AuthenticationFilter implements GlobalFilter {

    @Autowired
    SkipUrlProperties skipUrlProperties;

    @Autowired
    RedisLiveUtil redisLiveUtil;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        String path = exchange.getRequest().getURI().getPath();

        // 过滤不需要验证的请求
        if (skipUrl(path)) {
            log.info("请求放行{}", path);
            return chain.filter(exchange);
        }
        
        // 从请求头中获取token
        String token = exchange.getRequest().getHeaders().getFirst("token");
        if (Strings.isNullOrEmpty(token)){
            log.info("{}请求未携带token，已被拦截", path);
            return Mono.empty();
        }

        // 校验token
        // 从redis中获取该token对应的userId
        String redisKey = LoginRedisKeyGenerate.getUserLoginKey(token);
        if (!redisLiveUtil.hasKey(redisKey)){
            log.info("{}请求所携带的token{}不正确", path, token);
            return Mono.empty();
        }

        // 将得到的userId保存至请求头中，让下游微服务可以随时获取
        Long userId = redisLiveUtil.get(redisKey, Long.class);
        ServerWebExchange webExchange = writeHeader(exchange, String.valueOf(userId));
        // 这里就返回我们上面写入请求头之后的ServerWebExchange了
        return chain.filter(webExchange);
    }


    /**
     * 将userId添加进请求头中
     */
    private ServerWebExchange writeHeader(ServerWebExchange exchange, String userId) {
        ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate()
                .header("userId", userId)
                .build();
        return exchange.mutate().request(serverHttpRequest).build();
    }


    /**
     * 过滤掉不需要进行认证的请求
     *
     * @param path 当前请求路径
     * @return true表示改请求不需要校验token
     */
    private boolean skipUrl(String path) {
        //路径匹配器(简介SpringMvc拦截器的匹配器)
        //比如/oauth/** 可以匹配/oauth/token    /oauth/check_token等
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        for (String shouldSkipUrl : skipUrlProperties.getShouldSkipUrls()) {
            if (antPathMatcher.match(shouldSkipUrl, path)) {
                return true;
            }
        }
        return false;
    }
}
